package controller.backstage;

import com.alibaba.druid.util.StringUtils;
import com.google.gson.Gson;
import model.Result;
import model.bo.*;
import model.InnerResult;
import service.AdminService;
import service.impl.AdminServiceImpl;
import utils.HttpUtils;
import utils.ModelUtils;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import static model.InnerResult.Status.FULFILLED;

@WebServlet("/api/admin/admin/*")
public class AdminServlet extends HttpServlet {
    private AdminService adminService = new AdminServiceImpl();
    private final Gson GSON = new Gson();
    private final String URI_PREFIX = "/api/admin/admin/";

    private final Function<InnerResult, Result> FILLER = dto -> {
        if (dto.getStatus() == FULFILLED) {
            return Result.fulfill(dto.getObject());
        } else {
            return Result.reject(dto.getObject().toString());
        }
    };


    //Get
    private final Map<String, HttpUtils.HttpRequestHandler> GET_DISPATCHER;
    private final HttpUtils.HttpRequestHandler ALL_ADMINS = (req, resp, gson) -> {
        InnerResult dto = adminService.getAllAdmins();
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler DELETE_ADMINS = (req, resp, gson) -> {
        String id = req.getParameter("id");

        //检测传入参数的有效性
        if ("".equals(id) || !StringUtils.isNumber(id)) {
            resp.getWriter().print(gson.toJson(Result.reject("非法参数")));
            return;
        }
        if (Integer.parseInt(id) < 0) {
            resp.getWriter().print(gson.toJson(Result.reject("非法参数")));
            return;
        }

        InnerResult dto = adminService.deleteAdmins(id);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler GET_ADMINS_INFO = (req, resp, gson) -> {
        String id = req.getParameter("id");

        //检测传入参数的有效性
        if ("".equals(id) || !StringUtils.isNumber(id)) {
            resp.getWriter().print(gson.toJson(Result.reject("非法参数")));
            return;
        }
        if (Integer.parseInt(id) < 0) {
            resp.getWriter().print(gson.toJson(Result.reject("非法参数")));
            return;
        }

        InnerResult dto = adminService.getAdminsInfo(id);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };


    //Post
    private final Map<String, HttpUtils.HttpRequestHandler> POST_DISPATCHER;
    private final HttpUtils.HttpRequestHandler LOGOUT_ADMIN = (req, resp, gson) -> {
        Cookie[] cookies = req.getCookies();
        HttpSession session = req.getSession();
        for (Cookie c : cookies) {
            if ("JSESSIONID".equals(c.getName()) && session.getId().equals(c.getValue())) {
                c.setMaxAge(0);
                resp.addCookie(c);
                break;
            }
        }
        resp.getWriter().print(gson.toJson(Result.fulfill()));
    };
    private final HttpUtils.HttpRequestHandler LOGIN = (req, resp, gson) -> {
        //获取请求中的JSON登录信息，并转为Java对象
        String requestBody = HttpUtils.getRequestBody(req);
        AdminBO admin = gson.fromJson(requestBody, AdminBO.class);

        //判断是否为空
        if (ModelUtils.isInvalid(admin, Arrays.asList("email", "pwd"))) {
            resp.getWriter().print(gson.toJson(Result.reject("请输入登录信息")));
            return;
        }

        //调用下层服务检测登录信息的有效性，并将结果返回前端
        InnerResult dto = adminService.validateLoginInfo(admin);
        if (dto.getStatus().equals(FULFILLED)) {
            HttpSession session = req.getSession();
            session.setAttribute("admin", "admin");
            Cookie cookie = new Cookie("JSESSIONID", session.getId());
            cookie.setMaxAge(7200);
            resp.addCookie(cookie);
        }
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler CHANGE_PWD = (req, resp, gson) -> {
        String requestBody = HttpUtils.getRequestBody(req);
        AdminChangePwdBO admin = gson.fromJson(requestBody, AdminChangePwdBO.class);

        if (ModelUtils.isInvalid(admin, Arrays.asList("adminToken", "newPwd", "oldPwd"))) {
            resp.getWriter().print(gson.toJson(Result.reject("信息不能为空")));
            return;
        }

        if (!admin.getNewPwd().equals(admin.getConfirmPwd())) {
            resp.getWriter().print(gson.toJson(Result.reject("新密码与确认密码不相同")));
            return;
        }

        InnerResult dto = adminService.changePwd(admin);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler UPDATE_ADMINSS = (req, resp, gson) -> {
        String requestBody = HttpUtils.getRequestBody(req);
        AdminBO admin = gson.fromJson(requestBody, AdminBO.class);

        if (ModelUtils.isInvalid(admin, Collections.singletonList("id"))) {
            resp.getWriter().print(gson.toJson(Result.reject("非法参数")));
            return;
        }

        if (ModelUtils.isInvalid(admin, Arrays.asList("nickname", "email", "pwd"))) {
            resp.getWriter().print(gson.toJson(Result.reject("信息不能为空")));
            return;
        }

        InnerResult dto = adminService.updateAdminss(admin);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler ADD_ADMINSS = (req, resp, gson) -> {
        String requestBody = HttpUtils.getRequestBody(req);
        AdminBO admin = gson.fromJson(requestBody, AdminBO.class);

        if (ModelUtils.isInvalid(admin, Arrays.asList("email", "pwd", "nickname"))) {
            resp.getWriter().print(gson.toJson(Result.reject("信息不能为空")));
            return;
        }

        InnerResult dto = adminService.addAdminss(admin);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };
    private final HttpUtils.HttpRequestHandler GET_SEARCH_ADMINS = (req, resp, gson) -> {
        String requestBody = HttpUtils.getRequestBody(req);
        AdminBO admin = gson.fromJson(requestBody, AdminBO.class);

        if (null == admin || (null == admin.getNickname() && null == admin.getEmail())) {
            InnerResult dto = adminService.getAllAdmins();
            resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
            return;
        }

        InnerResult dto = adminService.getSearchAdmins(admin);
        resp.getWriter().print(gson.toJson(FILLER.apply(dto)));
    };

    public AdminServlet() {
        super();
        //Get Handler初始化
        HashMap<String, HttpUtils.HttpRequestHandler> getDispatcher = new HashMap<>();
        getDispatcher.put("allAdmins", ALL_ADMINS);
        getDispatcher.put("deleteAdmins", DELETE_ADMINS);
        getDispatcher.put("getAdminsInfo", GET_ADMINS_INFO);
        this.GET_DISPATCHER = Collections.unmodifiableMap(getDispatcher);

        //Post Handler初始化
        HashMap<String, HttpUtils.HttpRequestHandler> postDispatcher = new HashMap<>();
        postDispatcher.put("logoutAdmin", LOGOUT_ADMIN);
        postDispatcher.put("login", LOGIN);
        postDispatcher.put("changePwd", CHANGE_PWD);
        postDispatcher.put("updateAdminss", UPDATE_ADMINSS);
        postDispatcher.put("addAdminss", ADD_ADMINSS);
        postDispatcher.put("getSearchAdmins", GET_SEARCH_ADMINS);
        this.POST_DISPATCHER = Collections.unmodifiableMap(postDispatcher);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        //将get action分发到对应的handler上
        try {
            GET_DISPATCHER
                    .get(req.getRequestURI()
                            .replace(URI_PREFIX, ""))
                    .handle(req, resp, GSON);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        //将post action分发到对应的handler上
        try {
            POST_DISPATCHER
                    .get(req.getRequestURI()
                            .replace(URI_PREFIX, ""))
                    .handle(req, resp, GSON);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
